﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using RelationExpertSystem.Relation;
using System.Diagnostics;

namespace RelationExpertSystem.Models
{
    public class PeopleModel
    {
        private IEnumerable<Person> _people;
        private IEnumerable<PersonPair> _pairs;

        string _fileName;
        public string FileName
        {
            get { return _fileName; }
        }

        public event EventHandler<FactsEventArgs> FactsLoaded;
        private void RaiseFactsLoaded(FactsEventArgs args)
        {
            EventHandler<FactsEventArgs> eh = FactsLoaded;
            if (eh != null)
                eh(this, args);
        }

        public event EventHandler<FactsEventArgs> FactsUpdated;
        private void RaiseFactsUpdated(FactsEventArgs args)
        {
            EventHandler<FactsEventArgs> eh = FactsUpdated;
            if (eh != null)
                eh(this, args);
        }

        public PeopleModel(string filePath)
        {
            _people = new List<Person>();
            _fileName = filePath;
        }

        public void LoadPeople()
        {
            // is this a new load, or a re-load of the same people?
            // in either case, actually, should be whole new session
            do
            {
                OpenFileDialog fd = new OpenFileDialog();
                fd.DefaultExt = "people";
                fd.AddExtension = true;
                fd.Filter = "People file (*.people)|*.people";
                if (fd.ShowDialog() != DialogResult.OK)
                    return;
                _fileName = fd.FileName;
            } while (_fileName == null || !File.Exists(_fileName));

            PeopleFileParser parser = new PeopleFileParser();
            _people = parser.Load(_fileName);
            //_people = new TestPeopleBuilder().GetPeople(); // shortcut to convert hard-coded tree to XML
            _pairs = null;
            RaiseFactsLoaded(new FactsEventArgs(BuildFactMessages()));
            return;
        }

        public void NewPeople()
        {
            _people = new List<Person>();
            _fileName = null;
            _pairs = null;
            RaiseFactsLoaded(new FactsEventArgs(BuildFactMessages()));
        }

        public void UpdatePeople(List<Person> people)
        {
            _people = people.ShallowCopy();
            _pairs = null;
            RaiseFactsUpdated(new FactsEventArgs(BuildFactMessages()));
        }

        public void SavePeople()
        {
            while (_fileName == null)
            {
                SaveFileDialog fd = new SaveFileDialog();
                fd.DefaultExt = "people";
                fd.AddExtension = true;
                fd.Filter = "People file (*.people)|*.people";
                if (fd.ShowDialog() != DialogResult.OK)
                    return;

                _fileName = fd.FileName;
            }

            PeopleFileParser parser = new PeopleFileParser();
            parser.Save(_people, _fileName);
        }

        public IEnumerable<Person> GetPeople()
        {
            return _people.ShallowCopy();
        }

        public void ClearInferredRelations()
        {
            foreach (Person p in _people)
                p.ClearRelations();
        }

        protected List<string> BuildFactMessages()
        {
            List<string> factMessages = new List<string>();
            foreach (Person p in _people)
            {
                // pseron sex
                factMessages.Add(String.Format("{0} is {1}", p.Name, p.Sex));
                // Person father
                if (!Person.IsNull(p.Father))
                    factMessages.Add(String.Format("{0} is {1}'s {2}", p.Father.Name, p.Name, Father.Instance.GetType().GetShortName()));
                // person mother
                if (!Person.IsNull(p.Mother))
                    factMessages.Add(String.Format("{0} is {1}'s {2}", p.Mother.Name, p.Name, Mother.Instance.GetType().GetShortName()));
                // person spouse
                if (!Person.IsNull(p.Spouse))
                    factMessages.Add(String.Format("{0} is {1}'s {2}", p.Spouse.Name, p.Name, Spouse.Instance.GetType().GetShortName()));
            }

            foreach (string message in factMessages)
                Debug.WriteLine("Fact: " + message);

            return factMessages;
        }

        public void BuildPairs()
        {
            List<PersonPair> pairs = new List<PersonPair>();
            foreach (Person p1 in _people)
            {
                foreach (Person p2 in _people)
                {
                    if (p1 == p2)
                        continue;

                    pairs.Add(new PersonPair(p1, p2)); // automatically get pair-up twice; once for each order
                }
            }
            _pairs = pairs;
        }

        public IEnumerable<IRuleTarget<RelationEventArgs>> GetPairs()
        {
            if (_pairs == null)
                BuildPairs();

            return _pairs;
        }
    }
}
